package com.ihrm.modules.sys.service.impl;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ihrm.common.exception.RRException;
import com.ihrm.common.utils.DownloadUtils;
import com.ihrm.common.utils.JwtUtils;
import com.ihrm.common.utils.PageUtils;
import com.ihrm.common.utils.Query;
import com.ihrm.modules.sys.dao.PermissionDao;
import com.ihrm.modules.sys.dao.UserDao;
import com.ihrm.modules.sys.entity.PermissionEntity;
import com.ihrm.modules.sys.entity.UserEntity;
import com.ihrm.modules.sys.service.UserService;
import com.ihrm.modules.sys.shiro.ShiroUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.omg.CORBA.OBJ_ADAPTER;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.*;


@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private PermissionDao permissionDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String companyId = params.containsKey("companyId") ? (String) params.get("companyId") : null;
        String departmentId = params.containsKey("departmentId") ? (String) params.get("departmentId") : null;

        IPage<UserEntity> page = userDao.queryPage(new Query<UserEntity>().getPage(params), companyId, departmentId);

        return new PageUtils(page);
    }

    @Override
    public void assignRoles(Map<String, Object> map) {
        // 清空用户之前分配的角色
        String id = (String) map.get("id");
        // 考虑先查询是否与userId 有在删除
        // 是否有其他优化方案
        userDao.deleteRolesByUserId(id);
        // 分配新角色
        int i = userDao.assignRoles(map);
        if (i <= 0) {
            throw new RRException("分配角色失败");
        }
    }

    @Override
    public String login(Map<String, Object> map) {

        String mobile = (String) map.get("mobile");
        String password = (String) map.get("password");
        UserEntity userEntity = userDao.selectOne(new QueryWrapper<UserEntity>().eq("mobile", mobile));

        if (userEntity == null || !StringUtils.equals(password, userEntity.getPassword())) {
            throw new RRException("用户名或者密码错误");
        }
        List<String> apis = permissionDao.queryBtnsByUserId(userEntity.getId());
        Map<String, Object> m = new HashMap<>();
        m.put("companyId", userEntity.getCompanyId());
        m.put("companyName", userEntity.getCompanyName());
        m.put("userId", userEntity.getId());
        m.put("apis", apis);
        return jwtUtils.createJwt(userEntity.getId(), userEntity.getUsername(), m);
    }

    private List<PermissionEntity> queryLevelMenusByUserId(String id) {

        List<PermissionEntity> menus = permissionDao.queryMenusByUserId(id);

        // 1、如果是集合为空结束
        if (CollectionUtils.isEmpty(menus)) {
            return null;
        }
        PermissionEntity root = new PermissionEntity();
        root.setId("0");
        LinkedList<PermissionEntity> stack = new LinkedList<>();
        stack.push(root);

        while (!stack.isEmpty() && menus.size() > 0) {
            PermissionEntity m = stack.pop();
            List<PermissionEntity> children = new LinkedList<>();
            Iterator<PermissionEntity> iterator = menus.iterator();
            while (iterator.hasNext()) {
                PermissionEntity next = iterator.next();
                if (StringUtils.equals(m.getId(), next.getPid())) {
                    // 2.1、找到元素，加入子集合；同时删除在原有集合中移除
//                    next.setParent(m);
                    children.add(next);
                    iterator.remove();
                }
            }
            if (children.size() > 0) {
                // 3、子集合不为空，封装层级数据

                m.setChildren(children);
                stack.addAll(children);
//                for (PermissionEntity x: children) {
//                    stack.push(x);
//                }
            }
        }
        return root.getChildren();
    }

//    @Override
//    public Map<String, Object> profile(String token) {
//
//        // 解析token，获取claims
//        Claims claims = jwtUtils.parseJwt(token);
//////        System.out.println(claims);
////        String id = claims.getId();
////        Object o = claims.get("jti");
//        String userId = (String) claims.get("userId");
////        System.out.println(claims.get("userId"));
//
//        // 获取用户信息
//        UserEntity userEntity = userDao.selectById(userId);
//        // 根据用户id获取权限
//        // 获取菜单权限
//        List<PermissionEntity> menus = queryLevelMenusByUserId(userId);
//        // 获取按钮权限
//        List<String> btns = permissionDao.queryBtnsByUserId(userId);
//
//        Map<String, Object> userInfo  = new HashMap<>();
//        userInfo.put("user", userEntity);
//        if (CollectionUtils.isNotEmpty(menus)) {
//            userInfo.put("menus", menus);
//        }
//        if (CollectionUtils.isNotEmpty(btns)) {
//            userInfo.put("btns", btns);
//        }
//       return userInfo;
//    }


    @Override
    public Map<String, Object> profile(UserEntity userEntity) {
        // 根据用户id获取权限
        // 获取菜单权限
        List<PermissionEntity> menus = queryLevelMenusByUserId(userEntity.getId());
        // 获取按钮权限
        List<String> btns = permissionDao.queryBtnsByUserId(userEntity.getId());

        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("user", userEntity);
        if (CollectionUtils.isNotEmpty(menus)) {
            userInfo.put("menus", menus);
        }
        if (CollectionUtils.isNotEmpty(btns)) {
            userInfo.put("btns", btns);
        }
        return userInfo;
    }

    @Override
    public void importFile(MultipartFile file) throws IOException {

        // 1、创建工作簿
        Workbook workbook = new XSSFWorkbook(file.getInputStream());
        // 2、获取表
        Sheet sheet = workbook.getSheetAt(0);

        // 构建用户列表
        List<UserEntity> users = new ArrayList<>();
        // 3、遍历行
        for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {

            Row row = sheet.getRow(rowNum);
            // 构建用户
            UserEntity userEntity = new UserEntity();
            Object[] vals = new Object[row.getLastCellNum()];
            // 遍历列
            for (int colNum = 1; colNum < row.getLastCellNum(); colNum++) {
                Cell cell = row.getCell(colNum);
                Object obj = getCellValue(cell);
                vals[colNum] = obj;
            }
            // 解决excel中数字过长转化为科学计数法的问题
            DecimalFormat decimalFormat = new DecimalFormat("0");
            String mobile = decimalFormat.format(vals[2]);
//            String departmentId = decimalFormat.format(vals[6]);
            userEntity.setUsername(vals[1].toString());
            userEntity.setMobile(mobile);
            userEntity.setJobNumber(decimalFormat.format(vals[3]));
            // 解决整数上传后带小数点的问题
            userEntity.setEmploymentForm(((Double) vals[4]).intValue());
            userEntity.setEntryTime((Date) vals[5]);
//            userEntity.setDepartmentId(departmentId);
            userEntity.setDepartmentId(vals[6].toString());
            userEntity.setPassword(ShiroUtils.md5("123456", mobile));
            users.add(userEntity);
        }

        // 用户数据批量插入用户表
        this.saveBatch(users);
    }

    @Override
    public void export(String month, HttpServletResponse response) throws IOException {
        // 设置下载文件信息
//        String fileName = URLEncoder.encode(String.format("%s.xlsx", "订单数据"),
//                StandardCharsets.UTF_8.toString());
////        response.setContentType("application/octet-stream");
//        response.setContentType("application/force-download");
        response.setContentType("application/octet-stream");
        String fileName = month + ".xlsx";
        fileName = response.encodeURL(new String(fileName.getBytes(), "iso8859-1"));
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        ExcelWriter writer = new ExcelWriterBuilder()
                .autoCloseStream(true)
                .excelType(ExcelTypeEnum.XLSX)
                .file(response.getOutputStream())
                .head(UserEntity.class)
                .build();
        // xlsx文件上上限是104W行左右,这里如果超过104W需要分Sheet
        WriteSheet writeSheet = new WriteSheet();
        writeSheet.setSheetName("sheet");

        // 获取表格数据
        List<UserEntity> list = new LambdaQueryChainWrapper<>(userDao)
                .likeRight(UserEntity::getEntryTime, month)
                .select(UserEntity::getId, UserEntity::getMobile, UserEntity::getUsername, UserEntity::getEntryTime,
                        UserEntity::getJobNumber)
                .list();
        // 填充导出数据
        writer.write(list, writeSheet);
        writer.finish();
    }

//    @Override
//    public void export(String month, HttpServletResponse response) throws IOException {
//        // 1、获取报表数据
//        List<UserEntity> list = new LambdaQueryChainWrapper<>(userDao)
//                .likeRight(UserEntity::getEntryTime, month)
//                .select(UserEntity::getId, UserEntity::getMobile, UserEntity::getUsername, UserEntity::getEntryTime,
//                        UserEntity::getEmploymentForm, UserEntity::getJobNumber)
//                .list();
//        // 2、构建Excel
//        Workbook wb = new XSSFWorkbook();
//        Sheet sheet = wb.createSheet();
//
//        // 构建表头
//        Row row = sheet.createRow(0);
//        String[] titles = "编号,手机号,用户名,入职时间,聘用形式,工号".split(",");
//        for (int i = 0; i < titles.length; i++) {
//            Cell cell = row.createCell(i);
//            cell.setCellValue(titles[i]);
//        }
//
//        // 填充数据
//        for (int i = 0; i < list.size(); i++) {
//            UserEntity userEntity = list.get(i);
//            row = sheet.createRow(i + 1);
//
//            Cell cell = row.createCell(0);
//            cell.setCellValue(userEntity.getId());
//            cell = row.createCell(1);
//            cell.setCellValue(userEntity.getMobile());
//            cell = row.createCell(2);
//            cell.setCellValue(userEntity.getUsername());
//            cell = row.createCell(3);
//            cell.setCellValue(userEntity.getEntryTime());
//            cell = row.createCell(4);
//            cell.setCellValue(userEntity.getEmploymentForm());
//            cell = row.createCell(5);
//            cell.setCellValue(userEntity.getJobNumber());
//        }
//        // 3、下载
//        ByteArrayOutputStream byteArrayOutputStream  = new ByteArrayOutputStream();
//        wb.write(byteArrayOutputStream);
//        DownloadUtils.download(byteArrayOutputStream, response, month + "人事报表.xlsx");
//    }

    private Object getCellValue(Cell cell) {

        // 获取单元格属性类型
        CellType cellType = cell.getCellType();
        Object value = null;

        switch (cellType) {
            case STRING:
                value = cell.getStringCellValue();
                break;
            case BOOLEAN:
                value = cell.getBooleanCellValue();
                break;
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    // 日期
                    value = cell.getDateCellValue();
                } else {
                    // 数字
                    value = cell.getNumericCellValue();
                }
                break;
            case FORMULA:
                // 公式
                value = cell.getCellFormula();
                break;
            default:
                break;
        }

        return value;
    }
}
